﻿using Furion;
using Furion.DatabaseAccessor;
using Furion.DataEncryption;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException; 
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using tlBasic.Core;
using Yitter.IdGenerator;

namespace tlBasic.Application
{
    /// <summary>
    /// 登录授权
    /// </summary>
    [ApiDescriptionSettings("登录权限", Order = 1)]
    public class RBACService : IDynamicApiController, ITransient
    {
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly SqlSugarRepository<cts_User> _userRep;
        private readonly SqlSugarRepository<cts_UserRole> _userRoleRep;
        private readonly SqlSugarRepository<sys_Menu> _sysMenuRep;
        private readonly SqlSugarRepository<cts_Role> _roleRep;
        private readonly SqlSugarRepository<cts_RoleMenu> _rolemenuRep; 
        private readonly ISysCacheService _cacheService;
        public string ServiceUrl = App.Configuration["ServiceConfig:Url"];
        public string PingGuUrl = App.Configuration["ServiceConfig:PingGuUrl"];
        public RBACService(IHttpContextAccessor httpContextAccessor
            , SqlSugarRepository<cts_User> userRep
            , SqlSugarRepository<cts_UserRole> userRoleRep
            , SqlSugarRepository<sys_Menu> sysMenuRep
            , SqlSugarRepository<cts_Role> roleRep
            , SqlSugarRepository<cts_RoleMenu> rolemenuRep 
            , ISysCacheService cacheService

            )
        {
            _httpContextAccessor = httpContextAccessor;
            _userRep = userRep;
            _sysMenuRep = sysMenuRep;
            _roleRep = roleRep;
            _rolemenuRep = rolemenuRep; 
            _userRoleRep = userRoleRep;  
            _cacheService = cacheService;
        }

        #region 登录信息
        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [AllowAnonymous]
        public UserDto Login(LoginInput input)
        {
            var codeKey = AppStr.CaptchaKey + input.CodeKey;
            var code = RedisHelper.GetString(codeKey);

            RedisHelper.KeyDelete(codeKey);
            if (string.IsNullOrEmpty(code))
            {
                throw Oops.Bah("验证码已过期");
            }
            if (code != input.Code)
            {
                throw Oops.Bah("验证码不正确");
            }
            // 验证用户名和密码
            var user = _userRep.GetFirst(m => m.Account == input.Account);
            if (user == null)
            {
                throw Oops.Bah("账号不正确");
            }
            if (user.Status == StatusEnum.Disable)
            {
                throw Oops.Bah("账号已停用");
            }
            input.Password = DESEncryption.Encrypt(input.Password, user.PwdSalt); // 加密 

            if (!user.Password.Equals(input.Password))
            {
                throw Oops.Bah("密码不正确");
            }
            
            var output = user.Adapt<UserDto>();
            if (input.Password.Equals(AppStr.DeafultPwd))
            {
                output.InitPwd = 1;
            }
            output.Token = JWTEncryption.Encrypt(new Dictionary<string, object>()
            {

                { ClaimConst.UserId, user.Id },
                { ClaimConst.Account,user.Account },
                { ClaimConst.Name, user.Name },
                { ClaimConst.UserType, user.UserType }, 
                { ClaimConst.Timestamp, DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() },
            });
            _httpContextAccessor.HttpContext.SigninToSwagger(output.Token);
            _httpContextAccessor.HttpContext.Response.Headers["access-token"] = output.Token;

            return output;
        }

       

        /// <summary>
        /// 退出
        /// </summary>
        [AllowAnonymous]
        public void LogOut()
        {

        }

        /// <summary>
        /// 获取验证码
        /// </summary>
        /// <returns></returns>
        [AllowAnonymous]
        public CaptchaModel getCaptcha()
        {
            var captcha = CaptchaHelper.CreateCaptchaImage();
            captcha.Code = "";
            return captcha;
        }
        /// <summary>
        /// 查看用户信息
        /// </summary>
        public async Task<UserDto> GetUserInfo()
        {
            // 获取用户Id
            var userId = UserHelper.GetUserId();
            UserDto user = _userRep.GetById(userId).Adapt<UserDto>();
            if (user.UserType == UserType.System)
            {
                user.Access = await _sysMenuRep.AsQueryable().Select(m => m.PermissionKey).ToListAsync();
            }
            else
            {

                var menuIds = _userRep.AsQueryable()
                  .InnerJoin<cts_RoleMenu>((a, b) => a.RoleId == b.RoleId)
                  .Where((a, b) => a.Id == userId)
                  .Select((a, b) => b.MenuId).ToList();


                user.Access = _sysMenuRep.AsQueryable()
                    .Where(a => menuIds.Contains(a.Id))
                    .Select(a => a.PermissionKey).Distinct().ToList();
            }
            user.Menus = GetMenusIview();
            return user;
        }
        /// <summary>
        /// 修改密码
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public void UpdatePwd(UpdatePwdInput input)
        {
            var userId = UserHelper.GetUserId();
            var user = _userRep.GetById(userId);
            if (!user.Password.Equals(DESEncryption.Encrypt(input.OldPassword, user.PwdSalt)))
            {
                throw Oops.Bah("原密码不正确");
            }
            user.Password = DESEncryption.Encrypt(input.Password, user.PwdSalt);
            _userRep.AsUpdateable(user).UpdateColumns(it => new { it.Password }).ExecuteCommand();
            _cacheService.SetTokenChange(userId);
        }


        /// <summary>
        /// 获取用户Iview菜单集合
        /// </summary> 
        /// <returns></returns>
        [NonAction]
        private List<IviewAdminTreeNode> GetMenusIview()
        {
            var userId = UserHelper.GetUserId();
            var userType = UserHelper.GetUserType();
            var sysMenuList = new List<sys_Menu>();
            // 管理员则展示所有系统菜单
            if (userType == UserType.System)
            {
                sysMenuList = _sysMenuRep.AsQueryable()
                                               .Where(u => u.Type != MenuType.Btn)
                                               .OrderBy(u => new { u.Sort, u.Id }).ToList();
            }
            else
            {
                var menuIds = _userRep.AsQueryable()
                    .InnerJoin<cts_RoleMenu>((a, b) => a.RoleId == b.RoleId)
                    .Where((a, b) => a.Id == userId)
                    .Select((a, b) => b.MenuId).ToList();


                sysMenuList = _sysMenuRep.AsQueryable()
                    .Where(a => a.Type != MenuType.Btn && menuIds.Contains(a.Id))
                    .OrderBy(a => new { a.Sort, a.Id }).Select(a => a).Distinct().ToList();

            }
            // 转换成登录菜单
            var iviewTreeNodes = sysMenuList.Select(u => new IviewAdminTreeNode
            {
                id = u.Id,
                parentid = u.ParentId,
                path = u.Path,
                name = u.Name,
                component = u.Component,
                props = u.Props,
                propsinfo = u.PropsInfo,
                propstitle = u.PropsTitle,
                meta = new Meta
                {
                    title = u.Title,
                    icon = u.Icon,
                    hideInMenu = u.HideInMenu,
                    notCache = u.NotCache,
                    showAlways = true,
                    href = u.Href,
                    target = u.Type == MenuType.Url ? "_blank" : ""
                }
            }).ToList();

            return iviewTreeNodes;
        }
        #endregion
        #region 角色管理

        /// <summary>
        /// 获取角色
        /// </summary>
        /// <returns></returns>
        public Task<List<cts_Role>> GetRoles()
        {

            return _roleRep.AsQueryable().OrderBy(m => m.Sort).ToListAsync();

        }
       
        /// <summary>
        /// 保存
        /// </summary>
        /// <param name="input"></param>
        [SecurityDefine("role")]
        public void SaveRole(cts_Role input)
        {
            var oldCount = _roleRep.AsQueryable().Where(m => m.Name.Equals(input.Name) && m.Id != input.Id).Count();
            if (oldCount > 0)
            {
                throw Oops.Bah("角色已存在");
            }
         
            if (input.Id > 0)
            {
                _roleRep.Update(input);
            }
            else
            {
                _roleRep.Insert(input);
            }
        }
        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="id"></param>
        [SecurityDefine("role")]
        public void DeleteRole(long id)
        {
            _roleRep.AsUpdateable().SetColumns(it => it.IsDeleted == true).Where(it => it.Id == id).ExecuteCommand();
        }
        /// <summary>
        ///  授权角色菜单
        /// </summary>
        /// <param name="input"></param>
        [SecurityDefine("role")]
        [UnitOfWork]
        public void GrantRoleMenu(GrantMenuDto input)
        {
            _rolemenuRep.AsDeleteable().Where(m => m.RoleId == input.Id).ExecuteCommand();
            var list = new List<cts_RoleMenu>();
            foreach (var item in input.MenuIds)
            {
                list.Add(new cts_RoleMenu
                {
                    Id = YitIdHelper.NextId(),
                    RoleId = input.Id,
                    MenuId = item
                });
            }
            _rolemenuRep.InsertRange(list);
            _cacheService.DelByPattern(CacheConst.KeyPermission);
        }
        /// <summary>
        /// 获取角色菜单
        /// </summary>
        /// <param name="id"></param>
        public Task<List<cts_RoleMenu>> GetRoleMenu(long id)
        {
            return _rolemenuRep.AsQueryable().Where(m => m.RoleId == id).ToListAsync();
        }
        /// <summary>
        /// 获取权限
        /// </summary>
        /// <returns></returns>
        [NonAction]
        public List<string> GetPermission()
        {
            var userId = UserHelper.GetUserId();
            var permissions = _cacheService.GetPermission(userId);
            if (permissions == null || permissions.Count == 0)
            {
                permissions = _userRep.AsQueryable()
                 .InnerJoin<cts_Role>((a, b) => a.RoleId == b.Id)
                 .InnerJoin<cts_RoleMenu>((a, b, c) => b.Id == c.RoleId)
                 .InnerJoin<sys_Menu>((a, b, c, d) => c.MenuId == d.Id)
                 .Where(a => a.Id == userId).Select((a, b, c, d) => d.PermissionKey).Distinct().ToList();

                _cacheService.SetPermission(userId, permissions); // 缓存结果
            }
            return permissions;
        }


        /// <summary>
        /// 获取商户菜单
        /// </summary>
        /// <returns></returns>
        public async Task<List<SimpleMenuDto>> GetRoleMenuTreeList()
        {

            var menuList = await _sysMenuRep.AsQueryable()
                  .OrderBy(a => new { a.Sort, a.Id }).ToTreeAsync(u => u.children, u => u.ParentId, 0);
            return menuList.Adapt<List<SimpleMenuDto>>();
        }
        #endregion
 
        #region 员工管理
        /// <summary>
        /// 获取账号
        /// </summary>
        /// <returns></returns>

        public SqlSugarPagedList<cts_User> SearchUser(SearchUserInput input)
        {
            var userType = UserHelper.GetUserType(); 
            var search = _userRep.AsQueryable()
                .LeftJoin<cts_Role>((a, b) => a.RoleId == b.Id)

             .Where(a => a.UserType == input.type); 
           
            if (!string.IsNullOrEmpty(input.keyword))
            {
                search = search.Where(a => a.Name.Contains(input.keyword) || a.Account.Contains(input.keyword) || a.Phone.Contains(input.keyword));
            }
            if (input.status > 0)
            {
                search = search.Where(a => a.Status == input.status);
            } 
            return search.Select((a, b) => new cts_User
            {
                Id = a.Id.SelectAll(),
                RoleName = b.Name,
            }).ToPagedList(input.page, input.size);
        }



        /// <summary>
        /// 保存
        /// </summary>
        /// <param name="input"></param>
        [SecurityDefine("user")]
        [UnitOfWork]
        public void SaveUser(cts_User input)
        {
            if (string.IsNullOrEmpty(input.Account))
            {
                throw Oops.Bah("登录账号不能为空");
            }
            var oldCount = _userRep.AsQueryable().Where(m => m.Account.Equals(input.Account) && m.Id != input.Id).Count();
            if (oldCount > 0)
            {
                throw Oops.Bah("登录账号已存在");
            }
            var userType = UserHelper.GetUserType();
          
            if (input.Id > 0)
            {

                _userRep.AsUpdateable(input).IgnoreColumns(m => new { m.Password, m.PwdSalt }).ExecuteCommand();
                _cacheService.SetTokenChange(input.Id);
                _cacheService.ClearPermission(input.Id);
            }
            else
            {
                input.Id = YitIdHelper.NextId();
                input.PwdSalt = YitIdHelper.NextId().ToString();
                input.Password = DESEncryption.Encrypt(AppStr.DeafultPwd, input.PwdSalt); // 加密 
                _userRep.Insert(input);
            }

        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="id"></param>
        [SecurityDefine("user")]
        public void DeleteUser(long id)
        {
            if (id == UserHelper.GetUserId())
            {
                throw Oops.Bah("不能删除当前登录账号");
            }

            _userRep.AsUpdateable().SetColumns(it => it.IsDeleted == true).Where(it => it.Id == id).ExecuteCommand();
            _cacheService.SetTokenChange(id);
        }
        /// <summary>
        /// 重置密码
        /// </summary>
        /// <param name="id"></param>
        [SecurityDefine("user")]
        public void ResetUserPwd(long id)
        {
            var user = _userRep.GetById(id);
            user.Password = DESEncryption.Encrypt(AppStr.DeafultPwd, user.PwdSalt);
            _userRep.AsUpdateable(user).UpdateColumns(it => it.Password).ExecuteCommand();
            _cacheService.SetTokenChange(id);
        }



        /// <summary>
        /// 获取员工角色
        /// </summary>
        /// <param name="id"></param>
        public List<cts_UserRole> GetUserRole(long id)
        {
            return _userRoleRep.GetList(m => m.UserId == id);
        }


        /// <summary>
        ///  授权员工角色
        /// </summary>
        /// <param name="input"></param>
        [SecurityDefine("user")]
        [UnitOfWork]
        public void GrantUserRole(GrantMenuDto input)
        {
            _userRoleRep.Delete(m => input.Ids.Contains(m.UserId));
            var list = new List<cts_UserRole>();
            var roleIds = input.RoleIds.Distinct();
            foreach (var id in input.Ids)
            {
                foreach (var item in roleIds)
                {
                    list.Add(new cts_UserRole
                    {
                        Id = YitIdHelper.NextId(),
                        UserId = id,
                        RoleId = item
                    });
                }

            }
            _userRoleRep.InsertRange(list);
            foreach (var id in input.Ids)
            {
                _cacheService.SetTokenChange(id);
                _cacheService.ClearPermission(id);
            }
        }


        #endregion

        
    }
}
